/*
 jChecs: a Java chess game sample 

 Copyright (C) 2006-2011 by David Cotton

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package fr.free.jchecs.core;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;

/**
 * Classe utilitaire délivrant des instances de représentation d'un état de jeu.
 * 
 * @author David Cotton
 */
public final class BoardFactory {
	/** Log de la classe. */
	private static final Logger LOGGER = Logger.getLogger(BoardFactory.class
			.getName());

	/**
	 * Classe utilitaire : ne pas instancier.
	 */
	private BoardFactory() {
		// Rien de spécifique...
	}

	/**
	 * Renvoi une instance de description de l'état d'une partie.
	 * 
	 * @param pType
	 *            Type de la méthode de représentation de l'instance souhaitée.
	 * @param pEtat
	 *            Etat de la partie.
	 * @return Instance correspondante.
	 */
	public static MoveGenerator valueOf(final Type pType, final State pEtat) {
		assert pType != null;
		assert pEtat != null;

		MoveGenerator res = null;
		switch (pEtat) {
		case EMPTY:
			res = newInstance(pType.getClassName(), ArrayBoard.EMPTY);
			break;
		case STARTING:
			res = newInstance(pType.getClassName(), ArrayBoard.STARTING);
			break;
		default:
			assert false;
		}

		assert res != null;
		return res;
	}

	/**
	 * Renvoi une instance de générateur de mouvements, obtenue par réflexion.
	 * 
	 * @param pClassName
	 *            Nom de la classe.
	 * @param pInitialState
	 *            Etat initial.
	 * @return Nouvelle instance (ou null en cas d'erreur).
	 */
	private static MoveGenerator newInstance(final String pClassName,
			final Board pInitialState) {
		assert pClassName != null;
		assert pInitialState != null;

		MoveGenerator res = null;

		Class<?> cls = null;
		try {
			cls = Class.forName(pClassName);
		} catch (final ClassNotFoundException e1) {
			LOGGER.warning("Board class [" + pClassName + "] not found");
		}
		if (cls != null) {
			Constructor<?> cst = null;
			try {
				cst = cls.getDeclaredConstructor(Board.class);
			} catch (final SecurityException e) {
				LOGGER.warning("Security exception on class [" + pClassName
						+ ']');
			} catch (final NoSuchMethodException e) {
				LOGGER.warning("No such method: " + e.getLocalizedMessage());
			}
			if (cst != null) {
				Object o;
				try {
					o = cst.newInstance(pInitialState);
					if (o instanceof MoveGenerator) {
						res = (MoveGenerator) o;
					}
				} catch (final IllegalArgumentException e) {
					LOGGER.warning("Illegal argument:"
							+ e.getLocalizedMessage());
				} catch (final InstantiationException e) {
					LOGGER.warning("Instanciation exception:"
							+ e.getLocalizedMessage());
				} catch (final IllegalAccessException e) {
					LOGGER.warning("Illegal access:" + e.getLocalizedMessage());
				} catch (final InvocationTargetException e) {
					LOGGER.warning("Invocation target exception:"
							+ e.getLocalizedMessage());
				}
			}
		}

		return res;
	}

	/** Enumération des états initiaux reconnus. */
	public static enum State {
		/** Etat initial, sans pièces. */
		EMPTY,

		/** Etat initial standard. */
		STARTING;
	}

	/** Enumération des types de représentation d'une partie disponibles. */
	public static enum Type {
		/** Description basée sur un tableau à deux dimensions. */
		ARRAY("fr.free.jchecs.core.ArrayBoard"),

		/** Description basée sur un tableau bordé, à une dimension. */
		MAILBOX("fr.free.jchecs.core.MailboxBoard"),

		/** Description la plus rapide : actuellement équivalent à MAILBOX. */
		FASTEST("fr.free.jchecs.core.MailboxBoard"),

		/**
		 * Description basée sur un tableau à une dimension avec indice filtré
		 * par la valeur 0x88.
		 */
		X88("fr.free.jchecs.core.X88Board");

		/** Nom de la classe d'implémentation. */
		private final String _className;

		/**
		 * Instancie une nouvelle constante de type de MoveGenerator.
		 * 
		 * @param pClassName
		 *            Nom de la classe d'implémentation.
		 */
		private Type(final String pClassName) {
			assert pClassName != null;

			_className = pClassName;
		}

		/**
		 * Renvoi le nom de la classe.
		 * 
		 * @return Nom de la classe implémentant ce type.
		 */
		String getClassName() {
			return _className;
		}
	}
}
